package hr.ctg.service;

import hr.ctg.domain.action.GuidesActionBean;
import hr.ctg.domain.model.Mjesto;
import hr.ctg.domain.model.Otok;
import hr.ctg.domain.model.Park;
import hr.ctg.service.dao.DrzavaDAO;
import hr.ctg.service.dao.MjestoDAO;
import hr.ctg.service.dao.OtokDAO;
import hr.ctg.service.dao.ParkDAO;
import hr.ctg.service.work.Work;

import java.io.BufferedReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Scanner;

import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.async.Asynchronous;
import org.jboss.seam.annotations.async.Expiration;
import org.jboss.seam.annotations.async.IntervalDuration;
import org.jboss.seam.annotations.web.RequestParameter;
import org.jboss.seam.cache.CacheProvider;
import org.jboss.seam.log.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

@Name("panoramioService")
public class PanoramioService implements Work {
	private static final int COUNT = 20;
	private static final String URL = "http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=0&to="
			+ COUNT
			+ "&minx={minx}&miny={miny}&maxx={maxx}&maxy={maxy}&size=medium";

	@Logger
	Log log;
	@SuppressWarnings("unchecked")
	@In
	CacheProvider cacheProvider;
	@In
	MjestoDAO mjestoDAO;
	@In
	OtokDAO otokDAO;
	@In
	ParkDAO parkDAO;
	@In
	DrzavaDAO drzavaDAO;
	@In(create = true)
	GuidesActionBean guides;

	@RequestParameter
	Integer idMjesta;
	@RequestParameter
	Integer idOtoka;
	@RequestParameter
	Integer idParka;

	@SuppressWarnings("unchecked")
	private List<Map<String, String>> getPhotos(final double minLongituda,
			final double minLatituda, final double maxLongituda,
			final double maxLatituda) {
		List<Map<String, String>> urlList;
		String key = Double.toString(minLongituda)
				+ Double.toString(minLatituda) + Double.toString(maxLongituda)
				+ Double.toString(maxLatituda);
		List<Map<String, String>> cache = (List) cacheProvider.get("panoramio",
				key);
		if (cache == null) {
			urlList = new ArrayList<Map<String, String>>();
			java.net.URL url = null;
			try {
				url = new java.net.URL(URL.replace("{minx}",
						Double.toString(minLongituda)).replace("{miny}",
						Double.toString(minLatituda)).replace("{maxx}",
						Double.toString(maxLongituda)).replace("{maxy}",
						Double.toString(maxLatituda)));
			} catch (MalformedURLException e) {
				log.error(e.getMessage(), e);
				return Collections.EMPTY_LIST;
			}
			BufferedReader br = null;
			StringBuilder sb = new StringBuilder();
			try {
				br = new java.io.BufferedReader(new java.io.InputStreamReader(
						url.openStream()));
				String line = "";
				while ((line = br.readLine()) != null) {
					sb.append(line);
				}
			} catch (IOException e) {
				log.error(e.getMessage(), e);
				return Collections.EMPTY_LIST;
			}

			try {
				br.close();
			} catch (IOException e) {
				log.error(e.getMessage(), e);
				return Collections.EMPTY_LIST;
			}

			// System.out.println(sb.toString());

			JSONObject result;
			try {
				result = new JSONObject(sb.toString());
				JSONArray photoArray = (JSONArray) result.get("photos");
				for (int i = 0; i < photoArray.length(); i++) {
					Map map = new HashMap<String, String>();
					JSONObject photo = (JSONObject) photoArray.get(i);
					map.put("url", photo.get("photo_file_url"));
					map.put("title", photo.get("photo_title"));
					urlList.add(map);
					// System.out.println(photo.get("photo_file_url"));
				}
				cacheProvider.put("panoramio", key, urlList);
			} catch (JSONException e) {
				log.error(e.getMessage(), e);
				return Collections.EMPTY_LIST;
			}
		} else {
			urlList = cache;
		}
		return urlList;
	}

	@SuppressWarnings("unchecked")
	@Factory(value = "panoramioSlikeByMjesto")
	public List<Map<String, String>> getPhotosByMjesto() {
		if (idMjesta == null) {
			return Collections.EMPTY_LIST;
		}
		Mjesto m = mjestoDAO.find(idMjesta);
		if (m.getPanoramio() == null) {
			return Collections.EMPTY_LIST;
		}
		return getPhotos(m.getPanoramio());
	}

	private List<Map<String, String>> getPhotos(String urls) {
		List<Map<String, String>> urlList = new ArrayList<Map<String, String>>();
		Scanner urlsScanner = new Scanner(urls);
		urlsScanner.useDelimiter(";");
		while (urlsScanner.hasNext()) {
			try {
				Scanner urlScanner = new Scanner(urlsScanner.next());
				urlScanner.useDelimiter("_");
				Map<String, String> map = new HashMap<String, String>();
				map.put("title", urlScanner.next());
				map.put("url", urlScanner.next());
				urlList.add(map);
			} catch (NoSuchElementException e) {
			}
		}
		return urlList;
	}

	private List<Map<String, String>> getPhotosByMjesto(Mjesto m) {
		final double minLongitude = m.getLongituda() - 0.05;
		final double minLatitude = m.getLatituda() - 0.05;
		final double maxLongitude = m.getLongituda() + 0.05;
		final double maxLatitude = m.getLatituda() + 0.05;
		return getPhotos(minLongitude, minLatitude, maxLongitude, maxLatitude);
	}

	@SuppressWarnings("unchecked")
	@Factory(value = "panoramioSlikeByOtok")
	public List<Map<String, String>> getPhotosByOtok() {
		if (idOtoka == null) {
			return Collections.EMPTY_LIST;
		}
		Otok o = otokDAO.find(idOtoka);
		if (o.getPanoramio() == null) {
			return Collections.EMPTY_LIST;
		}
		return getPhotos(o.getPanoramio());
	}

	private List<Map<String, String>> getPhotosByOtok(Otok o) {
		final double minLongitude = o.getLongituda() - 0.25;
		final double minLatitude = o.getLatituda() - 0.07;
		final double maxLongitude = o.getLongituda() + 0.25;
		final double maxLatitude = o.getLatituda() + 0.07;
		return getPhotos(minLongitude, minLatitude, maxLongitude, maxLatitude);
	}

	@SuppressWarnings("unchecked")
	@Factory(value = "panoramioSlikeByPark")
	public List<Map<String, String>> getPhotosByPark() {
		Park p = parkDAO.find(idParka);
		if (p.getPanoramio() == null) {
			return Collections.EMPTY_LIST;
		}
		return getPhotos(p.getPanoramio());
	}

	private List<Map<String, String>> getPhotosByPark(Park p) {
		final double minLongitude = p.getLongituda() - 0.05;
		final double minLatitude = p.getLatituda() - 0.05;
		final double maxLongitude = p.getLongituda() + 0.05;
		final double maxLatitude = p.getLatituda() + 0.05;
		return getPhotos(minLongitude, minLatitude, maxLongitude, maxLatitude);
	}

	@SuppressWarnings("unchecked")
	@Factory("panoramioSlikeByDrzava")
	public List<Map<String, String>> getPhotosByCountry() {
		// Drzava d = drzavaDAO.find(1);
		// final double minLongitude = d.getLongituda() - 3;
		// final double minLatitude = d.getLatituda() - 2;
		// final double maxLongitude = d.getLongituda() + 3;
		// final double maxLatitude = d.getLatituda() + 2;
		List<Mjesto> mjestoList = mjestoDAO.findByPanormaioNotNull(100);
		if (mjestoList.size() > 0) {
			Mjesto m = mjestoList
					.get((int) (Math.random() * mjestoList.size()));
			if (m.getPanoramio() != null) {
				return getPhotos(m.getPanoramio());
			}
		}
		return Collections.EMPTY_LIST;
	}

	@Override
	@Asynchronous
	@Transactional
	public void process(@Expiration Date date, @IntervalDuration long duration) {
		process();
	}

	@Override
	@Asynchronous
	@Transactional
	public void process(@Expiration Date date) {
		process();
	}

	private void process() {
		log.info("PanoramioService je  poceo s radom");
		List<Mjesto> mjesta = mjestoDAO.findByLatLonOpisNotNull();
		for (Mjesto mjesto : mjesta) {
			List<Map<String, String>> urls = getPhotosByMjesto(mjesto);
			mjesto.setPanoramio("");
			for (Map<String, String> map : urls) {
				mjesto.setPanoramio(map.get("title") + "_" + map.get("url")
						+ ";" + mjesto.getPanoramio());
			}
			mjestoDAO.merge(mjesto);
			mjestoDAO.flush();
		}

		List<Otok> otoci = otokDAO.findByLatLonOpisNotNull();
		for (Otok otok : otoci) {
			List<Map<String, String>> urls = getPhotosByOtok(otok);
			otok.setPanoramio("");
			for (Map<String, String> map : urls) {
				otok.setPanoramio(map.get("title") + "_" + map.get("url") + ";"
						+ otok.getPanoramio());
			}
			otokDAO.merge(otok);
			otokDAO.flush();
		}

		List<Park> parkovi = parkDAO.findByLatLonNotNull();
		for (Park park : parkovi) {
			List<Map<String, String>> urls = getPhotosByPark(park);
			park.setPanoramio("");
			for (Map<String, String> map : urls) {
				park.setPanoramio(map.get("title") + "_" + map.get("url") + ";"
						+ park.getPanoramio());
			}
			parkDAO.merge(park);
			parkDAO.flush();
		}

		log.info("PanoramioService je  zavrsio s radom");
	}

}
